home *** CD-ROM | disk | FTP | other *** search
/ Aminet 8 / Aminet 8 (1995)(GTI - Schatztruhe)[!][Oct 1995].iso / Aminet / gfx / pbm / pnmtopng.lha / src / pnmtopng.c < prev    next >
C/C++ Source or Header  |  1995-07-15  |  9KB  |  351 lines

  1. /* pnmtopng.c - read a portable anymap and produce Public Networks Graphic file
  2. **
  3. ** derived from pnmtorast.c (c) 1990,1991 by Jef Poskanzer
  4. **
  5. ** Copyright (C) 1995 by Alexander Lehmann <alex@hal.rhein-main.de>
  6. **
  7. ** Permission to use, copy, modify, and distribute this software and its
  8. ** documentation for any purpose and without fee is hereby granted, provided
  9. ** that the above copyright notice appear in all copies and that both that
  10. ** copyright notice and this permission notice appear in supporting
  11. ** documentation.  This software is provided "as is" without express or
  12. ** implied warranty.
  13. */
  14.  
  15. #include "pnm.h"
  16. #include "png.h"
  17.  
  18. #include "ppmcmap.h"
  19. #define MAXCOLORS 256
  20.  
  21. static int verbose = 0;
  22.  
  23. int
  24. main( argc, argv )
  25.      int argc;
  26.      char* argv[];
  27. {
  28.   FILE* ifp;
  29.   xel** xels;
  30.   xel p;
  31.   colorhist_vector chv;
  32.   colorhash_table cht;
  33.   int argn, rows, cols, format, i;
  34.   int depth, colors;
  35.   xelval maxval;
  36.   int interlace, downscale;
  37.   double scaleval;
  38.   int x,y;
  39.   int gray;
  40.   int mayscale;
  41.   png_struct *png_ptr = malloc(sizeof (png_struct));
  42.   png_info *info_ptr = malloc(sizeof (png_info));
  43.   png_color palette[MAXCOLORS];
  44.   png_byte *line;
  45.   png_byte *pp;
  46.   int pass;
  47.   int color;
  48.   char* usage = "[-interlace] [-downscale] [pnmfile]";
  49.  
  50.   pnm_init( &argc, argv );
  51.  
  52.   argn = 1;
  53.   interlace=0;
  54.   downscale=0;
  55.  
  56.   while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
  57.     {
  58.       if ( pm_keymatch( argv[argn], "-verbose", 2 ) )
  59.         verbose=1;
  60.       else
  61.       if ( pm_keymatch( argv[argn], "-interlace", 2 ) )
  62.         interlace=1;
  63.       else
  64.       if ( pm_keymatch( argv[argn], "-downscale", 2 ) )
  65.         downscale=1;
  66.       else
  67.             pm_usage( usage );
  68.       ++argn;
  69.     }
  70.  
  71.   if ( argn != argc )
  72.     {
  73.       ifp = pm_openr( argv[argn] );
  74.       ++argn;
  75.     }
  76.   else
  77.     ifp = stdin;
  78.  
  79.   if ( argn != argc )
  80.     pm_usage( usage );
  81.  
  82.   xels = pnm_readpnm( ifp, &cols, &rows, &maxval, &format );
  83.  
  84.   pm_close( ifp );
  85.  
  86.   /* first of all, check if we have a grayscale written as PPM */
  87.  
  88.   gray=1;
  89.   if(PNM_FORMAT_TYPE(format)==PPM_TYPE) {
  90.     for(x=0;x<cols;x++)
  91.       for(y=0;y<rows;y++) {
  92.         p=xels[y][x];
  93.         if(PPM_GETR(p)!=PPM_GETG(p) || PPM_GETG(p)!=PPM_GETB(p)) {
  94.           gray=0;
  95.           goto break2a;
  96.         }
  97.       }
  98. break2a:
  99.     if(gray) format=PGM_TYPE;
  100.   }
  101.  
  102.   /* handle `odd' maxvalues */
  103.  
  104.   if(PNM_FORMAT_TYPE(format)!=PBM_TYPE) {
  105.     if(maxval>65535 && !downscale)
  106.       pm_error("can only handle files up to 16 bit (use -downscale to override");
  107.  
  108.     if(maxval!=255 && maxval!=65535 &&
  109.        (PNM_FORMAT_TYPE(format)!=PGM_TYPE || (maxval!=1 && maxval!=3 &&
  110.         maxval!=15))) {
  111.       if(maxval<255) {
  112.         pm_message("rescaling to 8 bit");
  113.         scaleval=255.0;
  114.       } else {
  115.         pm_message("rescaling to 16 bit");
  116.         scaleval=65535.0;
  117.       }
  118.       for(y=0;y<rows;y++)
  119.         for(x=0;x<cols;x++) {
  120.           PPM_DEPTH(p, xels[y][x], maxval, scaleval);
  121.           xels[y][x]=p;
  122.         }
  123.       maxval=scaleval;
  124.     }
  125.   }
  126.  
  127.   /* check for 16 bit entries which are just scaled 8 bit entries, e.g.
  128.      when converting a 8 bit palette TIFF to ppm */
  129.  
  130.   if(PNM_FORMAT_TYPE(format)!=PBM_TYPE && maxval==65535) {
  131.     mayscale=1;
  132.     for(y=0;y<rows;y++)
  133.       for(x=0;x<cols;x++) {
  134.         p=xels[y][x];
  135.         if(PNM_FORMAT_TYPE(format)==PGM_TYPE ?
  136.            (PNM_GET1(p)&0xff)*0x101!=PNM_GET1(p) :
  137.            (PPM_GETR(p)&0xff)*0x101!=PPM_GETR(p) ||
  138.            (PPM_GETG(p)&0xff)*0x101!=PPM_GETG(p) ||
  139.            (PPM_GETB(p)&0xff)*0x101!=PPM_GETB(p)) {
  140.           mayscale=0;
  141.           goto break2b;
  142.         }
  143.       }
  144. break2b:
  145.     if(mayscale) {
  146.       pm_message("scaling to 8 bit (superflous 16 bit data)");
  147.       for(y=0;y<rows;y++)
  148.         for(x=0;x<cols;x++) {
  149.           p=xels[y][x];
  150.           if(PNM_FORMAT_TYPE(format)==PGM_TYPE) {
  151.             PNM_ASSIGN1(xels[y][x], PNM_GET1(p)&0xff);
  152.           } else {
  153.             PPM_ASSIGN(xels[y][x], PPM_GETR(p)&0xff,  PPM_GETG(p)&0xff,
  154.                        PPM_GETB(p)&0xff);
  155.           }
  156.         }
  157.       maxval=255;
  158.     }
  159.   }
  160.  
  161.   /* now the same thing for bit depth 4, 2 and 1, only for grayscale pics */
  162.  
  163.   if(PNM_FORMAT_TYPE(format)==PGM_TYPE && maxval==255) {
  164.       mayscale=1;
  165.       for(y=0;y<rows;y++)
  166.         for(x=0;x<cols;x++) {
  167.           if((PNM_GET1(xels[y][x])&0xf)*0x11!=PNM_GET1(xels[y][x]))
  168.             mayscale=0;
  169.           goto break2c;
  170.         }
  171. break2c:
  172.       if(mayscale) {
  173.         for(y=0;y<rows;y++)
  174.           for(x=0;x<cols;x++) {
  175.             PNM_ASSIGN1(xels[y][x], PNM_GET1(xels[y][x])&0xf);
  176.           }
  177.         maxval=15;
  178.       }
  179.     }
  180.  
  181.   if(PNM_FORMAT_TYPE(format)==PGM_TYPE && maxval==15) {
  182.     mayscale=1;
  183.     for(y=0;y<rows;y++)
  184.       for(x=0;x<cols;x++) {
  185.         if((PNM_GET1(xels[y][x])&3)*5!=PNM_GET1(xels[y][x]))
  186.           mayscale=0;
  187.         goto break2d;
  188.       }
  189. break2d:
  190.     if(mayscale) {
  191.       for(y=0;y<rows;y++)
  192.         for(x=0;x<cols;x++) {
  193.           PNM_ASSIGN1(xels[y][x], PNM_GET1(xels[y][x])&3);
  194.         }
  195.       maxval=3;
  196.     }
  197.   }
  198.  
  199.   if(PNM_FORMAT_TYPE(format)==PGM_TYPE && maxval==3) {
  200.     mayscale=1;
  201.     for(y=0;y<rows;y++)
  202.       for(x=0;x<cols;x++) {
  203.         if((PNM_GET1(xels[y][x])&1)*3!=PNM_GET1(xels[y][x]))
  204.           mayscale=0;
  205.         goto break2e;
  206.       }
  207. break2e:
  208.     if(mayscale) {
  209.       for(y=0;y<rows;y++)
  210.         for(x=0;x<cols;x++) {
  211.           PNM_ASSIGN1(xels[y][x], PNM_GET1(xels[y][x])&1);
  212.         }
  213.       maxval=1;
  214.     }
  215.   }
  216.  
  217.   /* Figure out the proper depth and colormap. */
  218.   switch ( PNM_FORMAT_TYPE(format) ) {
  219.   case PPM_TYPE:
  220.     if(maxval==255) {
  221.       pm_message( "computing colormap..." );
  222.       chv = ppm_computecolorhist( xels, cols, rows, MAXCOLORS, &colors );
  223.       if ( chv == (colorhist_vector) 0 ) {
  224.         pm_message("Too many colors - proceeding to write a 24-bit non-mapped" );
  225.         pm_message("image file.  If you want 8 bits, try doing a 'ppmquant %d'.",
  226.                    MAXCOLORS );
  227.         depth = 8;
  228.       } else {
  229.         pm_message( "%d colors found", colors );
  230.  
  231.         depth=8;
  232.         if(colors<=16) depth=4;
  233.         if(colors<=4) depth=2;
  234.         if(colors<=2) depth=1;
  235.  
  236.       }
  237.     } else {
  238.       depth=16;
  239.     }
  240.  
  241.     break;
  242.  
  243.   case PGM_TYPE:
  244.     if(maxval==65535)
  245.       depth=16;
  246.     else if(maxval==255)
  247.       depth=8;
  248.     else if(maxval==15)
  249.       depth=4;
  250.     else if(maxval==3)
  251.       depth=2;
  252.     else if(maxval==1)
  253.       depth=1;
  254.     else
  255.       pm_error("(can't happen) undefined maxvalue");
  256.     break;
  257.  
  258.   default:
  259.     depth = 1;
  260.     break;
  261.   }
  262.  
  263.   if(verbose)
  264.     pm_message("writing a %d bit %s file%s", depth,
  265.       PNM_FORMAT_TYPE(format)!=PPM_TYPE?"gray":(chv!=NULL?"palette":"rbg"),
  266.       interlace ? "(interlaced)" : "");
  267.  
  268.   /* now write the file */
  269.  
  270.   if(!setjmp(png_ptr->jmpbuf)) {
  271.     png_write_init(png_ptr);
  272.     png_info_init(info_ptr);
  273.     png_init_io(png_ptr, stdout);
  274.     info_ptr->width=cols;
  275.     info_ptr->height=rows;
  276.     info_ptr->bit_depth=depth;
  277.  
  278.     if(PNM_FORMAT_TYPE(format)==PPM_TYPE) {
  279.       info_ptr->color_type=chv!=NULL ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB;
  280.     } else {
  281.       info_ptr->color_type=PNG_COLOR_TYPE_GRAY;
  282.     }
  283.     info_ptr->interlace_type=interlace;
  284.  
  285.     if(info_ptr->color_type==PNG_COLOR_TYPE_PALETTE) {
  286.       for(i=0;i<MAXCOLORS;i++) {
  287.         palette[i].red=PPM_GETR(chv[i].color);
  288.         palette[i].green=PPM_GETG(chv[i].color);
  289.         palette[i].blue=PPM_GETB(chv[i].color);
  290.       }
  291.       info_ptr->palette=palette;
  292.       info_ptr->num_palette=colors;
  293.       info_ptr->valid |= PNG_INFO_PLTE;
  294.  
  295.       cht = ppm_colorhisttocolorhash( chv, colors );
  296.       ppm_freecolorhist( chv );
  297.     }
  298.  
  299.     png_write_info(png_ptr, info_ptr);
  300.  
  301.     png_set_packing(png_ptr);
  302.  
  303.     line=malloc(cols*6);
  304.  
  305.     for(pass=0;pass<png_set_interlace_handling(png_ptr);pass++) {
  306.       for(y=0;y<rows;y++) {
  307.         pp=line;
  308.         for(x=0;x<cols;x++) {
  309.           p=xels[y][x];
  310.           if(info_ptr->color_type==PNG_COLOR_TYPE_GRAY) {
  311.             if(depth==16) {
  312.               *pp++=PNM_GET1(p)>>8;
  313.             }
  314.             *pp++=PNM_GET1(p)&0xff;
  315.           } else if(info_ptr->color_type==PNG_COLOR_TYPE_PALETTE) {
  316.             color = ppm_lookupcolor( cht, &p);
  317.             *pp++=color;
  318.           } else {
  319.             if(depth==16) {
  320.               *pp++=PPM_GETR(p)>>8;
  321.             }
  322.             *pp++=PPM_GETR(p)&0xff;
  323.             if(depth==16) {
  324.               *pp++=PPM_GETG(p)>>8;
  325.             }
  326.             *pp++=PPM_GETG(p)&0xff;
  327.             if(depth==16) {
  328.               *pp++=PPM_GETB(p)>>8;
  329.             }
  330.             *pp++=PPM_GETB(p)&0xff;
  331.           }
  332.         }
  333.         png_write_row(png_ptr, line);
  334.       }
  335.     }
  336.  
  337.     png_write_end(png_ptr, info_ptr);
  338.     png_write_destroy(png_ptr);
  339.  
  340.     free(png_ptr);
  341.     free(info_ptr);
  342.  
  343.   } else {
  344.     pm_error("setjmp returns error condition");
  345.     free(png_ptr);
  346.     free(info_ptr);
  347.     exit(1);
  348.   }
  349.   exit( 0 );
  350. }
  351.